/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.cx1.service.utils;

import com.json.parsers.JSONParser;
import com.json.parsers.JsonParserFactory;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.cx1.model.Amenity;
import org.cx1.model.Listing;
import org.cx1.model.Photo;
import org.cx1.model.Place;
import org.cx1.model.utils.KFurnishTypeIDs;
import org.cx1.model.utils.KPlaceTypeIDs;
import org.cx1.model.utils.KPropertyTypeIDs;
import org.cx1.model.utils.KPropertyTypes;
import org.cx1.model.utils.KStatusTypeIDs;
import org.cx1.model.utils.ServiceResponse;
import org.cx1.model.utils.SystemProperties;
import org.cx1.service.api.IAmenityService;
import org.cx1.service.api.IListingService;
import org.cx1.service.api.IPhotoService;
import org.cx1.service.api.IPlaceService;
import org.cx1.service.impl.DAmenityService;
import org.cx1.service.impl.DListingService;
import org.cx1.service.impl.DPhotoService;
import org.cx1.service.impl.DPlaceService;
import org.cx1.service.impl.MAmenityService;
import org.cx1.service.impl.MListingService;
import org.cx1.service.impl.MPhotoService;
import org.cx1.service.impl.MPlaceService;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

/**
 *
 * @author ECH
 */
public class RoomoramaClient {

    public final static String API_URL_PROPERTIES_MAKATI = "http://api.roomorama.com/v1.0/rooms.xml?destination=Makati%20City%2C%20Metro%20Manila&limit=";
    public final static String API_URL_PROPERTIES_TAGUIG = "http://api.roomorama.com/v1.0/rooms.xml?destination=Taguig%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_MANDALUYONG = "http://api.roomorama.com/v1.0/rooms.xml?destination=Mandaluyong+City%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_PASIG = "http://api.roomorama.com/v1.0/rooms.xml?destination=Pasig+City%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_QUEZON_CITY = "http://api.roomorama.com/v1.0/rooms.xml?destination=Quezon+City%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_MANILA = "http://api.roomorama.com/v1.0/rooms.xml?destination=Manila%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_PASAY = "http://api.roomorama.com/v1.0/rooms.xml?destination=Pasay+City%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_PARANAQUE = "http://api.roomorama.com/v1.0/rooms.xml?destination=Paranaque%20City,%20Manila&limit=";
    public final static String API_URL_PROPERTIES_MUNTINLUPA = "http://api.roomorama.com/v1.0/rooms.xml?destination=Muntinlupa+City%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_SAN_JUAN = "http://api.roomorama.com/v1.0/rooms.xml?destination=San+Juan%2C+Metro+Manila&limit=";
    public final static String API_URL_PROPERTIES_CEBU = "http://api.roomorama.com/v1.0/rooms.xml?destination=Cebu+City%2C+Cebu&limit=";

    public final static String CITY_NAME_MAKATI = "Makati";
    public final static String CITY_NAME_TAGUIG = "Taguig";
    public final static String CITY_NAME_MANDALUYONG = "Mandaluyong";
    public final static String CITY_NAME_PASIG = "Pasig";
    public final static String CITY_NAME_QUEZON_CITY = "Quezon City";
    public final static String CITY_NAME_MANILA = "Manila";
    public final static String CITY_NAME_PASAY = "Pasay";
    public final static String CITY_NAME_PARANAQUE = "Paranaque";
    public final static String CITY_NAME_MUNTINLUPA = "Muntinlupa";
    public final static String CITY_NAME_SAN_JUAN = "San Juan";
    public final static String CITY_NAME_CEBU = "Cebu";
    
    private static double EXCG_RATE = 0.0;
    
    //private IListingService listingService = new MListingService();
    //private IPlaceService placeService = new MPlaceService();
    //private IPhotoService photoService = new MPhotoService();
    //private IAmenityService amenityService = new MAmenityService();
    
    private IListingService listingService = new DListingService();
    private IPlaceService placeService = new DPlaceService();
    private IPhotoService photoService = new DPhotoService();
    private IAmenityService amenityService = new DAmenityService();
        
    static {
        EXCG_RATE = RoomoramaClient.getUSDPHPExchangeRate();
    }
                
    public void reflectListings(String apiURL, String cityName, String limit) {
        Place city = null;
        List<Listing> cityListings = null;
        
        //CX: retrieve current roomorama rooms
        List<Room> rooms = this.searchRooms(apiURL, cityName, limit);
        Collections.reverse(rooms);
        
        //CX: retrieve city
        ServiceResponse<String> response1 = placeService.readIDByTitle(cityName);
        if (response1.isSuccessful() && !StringUtils.isEmpty(response1.getResponse())) {
            ServiceResponse<Place> response2 = placeService.read(response1.getResponse());
            city = response2.getResponse();
        }       
        
        //CX: retrieve city roomorama listings
        if (city != null) {
           ServiceResponse<List<Listing>> response3 = listingService.readPlaceListingsRoomorama(city.getId(), 0, 0);
           cityListings = response3.getResponse();
        }            
        
        if (rooms != null) {
            deleteNonExistingListingsByCity(rooms, cityListings);
            updateExistingiListingsByCity(rooms, city);
            addNewListingsByCity(rooms, city);
        }
    }
            
    public List<Room> searchRooms(String apiURL, String cityName, String limit) {
        List<Room> rooms = new ArrayList<Room>();
        try {
            HttpClient client = new HttpClient();
            GetMethod getMethod = new GetMethod(apiURL + limit);
            getMethod.addRequestHeader(new Header("Accept", "Text/xml"));

            client.executeMethod(getMethod);

            if (getMethod.getStatusCode() == HttpStatus.SC_OK) {
                String response = getMethod.getResponseBodyAsString();

                try {
                    SAXBuilder builder = new SAXBuilder();
                    Reader in = new StringReader(response);

                    Document document = builder.build(in);
                    Element rootNode = document.getRootElement().getChild("rooms");
                    //List<Element> list = rootNode.getChildren("room");

                    Element parentRoom = rootNode;

                    if (parentRoom != null) {

                        List<Element> roomList = parentRoom.getChildren();
                        if (roomList != null && roomList.size() > 0) {
                            for (Element record : roomList) {
                                if (!StringUtils.isEmpty(record.getChildText("id"))) {
                                    
                                    Room room = getRoomData(record.getChildText("id"));
                                    room.setCity(cityName);
                                    rooms.add(room);                                    
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rooms;
    }
    
    private Room getRoomData(String roomID) {
        Room room = null;
        String urlQuery = "https://api.roomorama.com/v1.0/rooms/-roomID-.xml";
        try {
            room = new Room();
            room.setId(roomID);

            urlQuery = urlQuery.replaceAll("-roomID-", roomID);

            HttpClient client = new HttpClient();
            GetMethod getMethod = new GetMethod(urlQuery);
            getMethod.addRequestHeader(new Header("Accept", "Text/xml"));

            client.executeMethod(getMethod);

            if (getMethod.getStatusCode() == HttpStatus.SC_OK) {
                String response = getMethod.getResponseBodyAsString();

                try {
                    SAXBuilder builder = new SAXBuilder();
                    Reader in = new StringReader(response);

                    Document document = builder.build(in);
                    Element rootNode = document.getRootElement();
                    Element roomNode = rootNode.getChild("room");

                    room.setType(roomNode.getChildText("type"));
                    room.setTitle(roomNode.getChildText("title"));
                    
                    if (StringUtils.isEmpty(room.getTitle())) {
                        System.out.println("WAT?");
                    }
                    
                    room.setDescription(roomNode.getChildText("description"));
                    room.setNumBedrooms(roomNode.getChildText("num_rooms"));
                    room.setNumBathrooms(roomNode.getChildText("num_bathrooms"));
                    room.setPrice(roomNode.getChildText("price"));
                    room.setCity(roomNode.getChildText("city"));
                    room.setLat(roomNode.getChildText("lat"));
                    room.setLng(roomNode.getChildText("lng"));

                    List<Element> images = roomNode.getChild("images").getChildren("image");
                    if (images != null && images.size() > 0) {
                        for (Element image : images) {
                            room.getImages().add(image.getChildText("image"));
                        }
                    }
                    
                    String amenities = roomNode.getChildText("amenities");
                    if (!StringUtils.isEmpty(amenities)) {
                        String[] amenityArr = amenities.split(",");
                        if (amenityArr != null && amenityArr.length > 0) {
                            for (int i=0; i < amenityArr.length; i++) {
                                room.getAmenities().add(amenityArr[i].trim());
                            }
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return room;
    }

    private void createListing(Room room, Place place) {
        try {
            ServiceResponse<Listing> response2 = listingService.readByRoomoramaID(room.getId());
            if (response2.getResponse() == null) {
                
                String titleType;
                String titleStruct;

                //CX: basic info
                Listing listing = new Listing();

                listing.setRoomoramaListing(true);
                listing.setRoomorama_id(room.getId());

                listing.setStatusTypeID(KStatusTypeIDs.FOR_RENT);
                listing.setPropertyTypeID(KPropertyTypeIDs.CONDOMINIUM);

                //CX: set lease term
                listing.setLeaseLongTerm(false);
                listing.setLeaseShortTerm(true);

                //CX: location and address
                listing.setLat(room.getLat());
                listing.setLng(room.getLng());

                titleStruct = listing.getStructure();

                //listing.setStreet("HV Dela Costa");
                listing.setCity(place.getTitle());
                listing.setRegion(place.getRegion());
                listing.setCountry("Philippines");

                //CX: property details
                listing.setFurnishTypeID(KFurnishTypeIDs.FULLY_FURNISHED);

                try {
                    listing.setNumBedrooms(StringUtils.isEmpty(room.getNumBedrooms()) ? 0 : Integer.parseInt(room.getNumBedrooms()));
                } catch (Exception ex) { }

                try {
                    listing.setNumBathrooms(StringUtils.isEmpty(room.getNumBathrooms()) ? 0 : Integer.parseInt(room.getNumBathrooms()));
                } catch (Exception ex) { }


                //CX: rate and availability
                //listing.setLongMonthRate(randLongMonthRates());

                double excgRate = EXCG_RATE;
                double shortDayRateUSD = StringUtils.isEmpty(room.getPrice()) ? 0 : Double.parseDouble(room.getPrice());
                double shortDayRatePHP = shortDayRateUSD * excgRate;

                DecimalFormat df = new DecimalFormat("0");
                listing.setShortDayRate(df.format(shortDayRatePHP));
                listing.setShortWeekRate(df.format(shortDayRatePHP*2));
                //listing.setShortMonthRate(randShortMonthRates());

                //CX: additional info            
                listing.setTitle(room.getTitle().trim().replaceAll("[^\\dA-Za-z0-9]", " ").replaceAll("  ", " "));
                listing.setDescription(room.getDescription().replaceAll("<br />", "<br>").replaceAll("<br><br><br>", "<br>"));

                //CX: back info
                listing.setVerified(false);

                //CX: place tags
                listing.getPlaceIDs().add(placeService.read(placeService.readIDByTitle(place.getTitle()).getResponse()).getResponse().getId());
                Place matchedPlace = extractPlace(room.getDescription());
                if (matchedPlace != null) {
                    listing.getPlaceIDs().add(matchedPlace.getId());
                }

                //CX: amenity tags
                if (room.getAmenities() != null && room.getAmenities().size() > 0) {
                    for (String amenity : room.getAmenities()) {
                        ServiceResponse<Amenity> sr1 = amenityService.readByTitle(amenity);
                        if (sr1.getResponse() != null) {
                            listing.getAmenityIDs().add(sr1.getResponse().getId());
                        }
                    }
                }

                System.out.println("CX: creating- " + listing.getTitle());
                ServiceResponse<String> response = listingService.create(listing, false, true, true);

                if (!StringUtils.isEmpty(response.getResponse())) {
                    //CX: post listing
                    listingService.postListing(response.getResponse());

                    //CX: add photos
                    List<Photo> photos = new ArrayList<Photo>();
                    if (room.getImages() != null && room.getImages().size() > 0) {

                        for (String imageURL : room.getImages()) {
                            String genFileName = UUID.randomUUID().toString();                        
                            String fileName = genFileName;
                            String ext = ".jpg";
                            fileName = fileName + ext;

                            String root = SystemProperties.PHOTO_DIRECTORY;
                            File path = new File(root);
                            File uploadedFile = new File(path + "/" + fileName );
                            File uploadedFile001 = new File(path + "/001-" + fileName );
                            File uploadedFile002 = new File(path + "/002-" + fileName );

                            if (!uploadedFile.exists()) {
                                //CX: write photo
                                FileUtils.copyURLToFile(new URL(imageURL), uploadedFile);
                                FileUtils.copyURLToFile(new URL(imageURL), uploadedFile001);
                                //FileUtils.copyURLToFile(new URL(imageURL), uploadedFile002);

                                //CX: write standard and preview sizes
                                ImageProcessor proc = new ImageProcessor();
                                //proc.createStandardSize(uploadedFile);
                                proc.createPreviewSize(uploadedFile);
                            }
                            photos.add(new Photo(root, fileName));
                        }       

                        if (photos != null && photos.size() > 0) {
                            for (Photo photo : photos) {
                                ServiceResponse<String> response1 = photoService.createListingPhoto(response.getResponse(), photo);                        
                            }                    
                        }
                    }
                    //listing.getPhotoIDs().add(randPhoto().getId());
                }        
                
            }
            
        } 
        catch (Exception ex) {
            System.out.println("CX: title- " + room.getId());
            System.out.println("CX: title- " + room.getTitle());
            ex.printStackTrace();
        }
    }
    
    private void updateListing(Room room, Place place) {
        try {            
            //CX: basic info
            ServiceResponse<Listing> response1 = listingService.readByRoomoramaID(room.getId());
            if (response1.isSuccessful() && response1.getResponse() != null) {
                
                Listing listing = response1.getResponse();

                //CX: location and address
                listing.setLat(room.getLat());
                listing.setLng(room.getLng());

                listing.setCity(place.getTitle());
                listing.setRegion(place.getRegion());
                listing.setCountry(place.getCountry());

                try {
                    listing.setNumBedrooms(StringUtils.isEmpty(room.getNumBedrooms()) ? 0 : Integer.parseInt(room.getNumBedrooms()));
                } catch (Exception ex) { }

                try {
                    listing.setNumBathrooms(StringUtils.isEmpty(room.getNumBathrooms()) ? 0 : Integer.parseInt(room.getNumBathrooms()));
                } catch (Exception ex) { }

                //CX: rate and availability
                double excgRate = EXCG_RATE;
                double shortDayRateUSD = StringUtils.isEmpty(room.getPrice()) ? 0 : Double.parseDouble(room.getPrice());
                double shortDayRatePHP = shortDayRateUSD * excgRate;

                DecimalFormat df = new DecimalFormat("0");
                listing.setShortDayRate(df.format(shortDayRatePHP));
                listing.setShortWeekRate(df.format(shortDayRatePHP*2));
                //listing.setShortMonthRate(randShortMonthRates());

                //CX: additional info         
                try {
                    listing.setTitle(room.getTitle().trim().replaceAll("[^\\dA-Za-z0-9]", " ").replaceAll("  ", " "));                    
                } catch (Exception ex) {
                    System.out.println("CX: exception- " + room.getTitle());
                }
                try {
                    listing.setDescription(room.getDescription().replaceAll("<br />", "<br>").replaceAll("<br><br><br>", "<br>"));                   
                } catch (Exception ex) {
                    System.out.println("CX: exception- " + room.getTitle());
                }
                
                //CX: place tags
                listing.getPlaceIDs().clear();
                listing.getPlaceIDs().add(place.getId());

                //CX: amenity tags
                listing.getAmenityIDs().clear();
                if (room.getAmenities() != null && room.getAmenities().size() > 0) {
                    for (String amenity : room.getAmenities()) {
                        ServiceResponse<Amenity> sr1 = amenityService.readByTitle(amenity);
                        if (sr1.getResponse() != null) {
                            listing.getAmenityIDs().add(sr1.getResponse().getId());
                        }
                    }
                }

                //CX: back info
                listing.setVerified(true);
                
                //CX: update listing
                ServiceResponse<Boolean> response = listingService.update(listing);
                
                //CX: re-post listing
                if (response.isSuccessful() && response.getResponse()) {
                    listingService.postListing(listing.getId());                    
                }
            }            
        } 
        catch (Exception ex) {
            System.out.println("CX: id- " + room.getId() + " title- " + room.getTitle() + " exception- " + ex.getMessage());
            //ex.printStackTrace();
        }
    }
        
    public void addNewListingsByCity(List<Room> rooms, Place city) {
        try {
            for (Room room : rooms) {
                if (listingService.readByRoomoramaID(room.getId()).getResponse() == null) {
                    System.out.println("CX: non-exist - " + room.getId());
                    createListing(room, city);
                }
            }            
        } catch (Exception ex) {
            
        }
    }
    
    public void updateExistingiListingsByCity(List<Room> rooms, Place place) {
        if (rooms != null && rooms.size() > 0) {
            for (Room room : rooms) {                
                this.updateListing(room, place);
            }
        }
    }
    
    public void deleteNonExistingListingsByCity(List<Room> rooms, List<Listing> placeListings) {
        if (rooms != null && rooms.size() > 0) {            
            if (placeListings != null && placeListings.size() > 0) {
                List<Listing> roomoramaListings = placeListings;

                for (Listing listing : roomoramaListings) {
                    boolean existing = false;
                    for (Room room : rooms) {
                        if (StringUtils.equalsIgnoreCase(listing.getRoomorama_id(), room.getId())) {
                            existing = true;
                        }
                    }
                    if (!existing) {
                        //CX: delete
                        System.out.println("CX: not existing on roomorama " + listing.getId());
                        listingService.delete(listing.getId());
                    }
                }
           }
        }
    }
    
    
    public static double getUSDPHPExchangeRate() {
        double excgRate = 43.0;    
        try {
            
            HttpClient client = new HttpClient();
            GetMethod getMethod = new GetMethod("http://openexchangerates.org/api/latest.json?app_id=34b9db344e3d4f0ea4af31d9234bdcca");
            getMethod.addRequestHeader(new Header("Accept", "Text/json"));

            client.executeMethod(getMethod);

            if (getMethod.getStatusCode() == HttpStatus.SC_OK) {
                String response = getMethod.getResponseBodyAsString();
                
                JsonParserFactory factory = JsonParserFactory.getInstance();
                JSONParser parser = factory.newJsonParser();
                Map jsonData = parser.parseJson(response);

                Map rates = (Map) jsonData.get("rates");
                excgRate = Double.parseDouble((String)rates.get("PHP"));
            }            
        } 
        catch (Exception ex) {
            ex.printStackTrace();           
        }
        return excgRate;
    }
    
    private Place extractPlace(String text) {
        Place matchedPlace = null;        
        if (matchedPlace == null) {
            ServiceResponse<List<Place>> sr1 = this.placeService.readAllByType(KPlaceTypeIDs.BUILDING, 0, 0);
            if (sr1.getResponse() != null && sr1.getResponse().size() > 0) {
                for (Place place : sr1.getResponse()) {
                    if (StringUtils.equalsIgnoreCase(text, place.getTitle())) {
                        matchedPlace = place;
                        break;
                    }
                }
            }  
        }
        
        if (matchedPlace == null) {
            ServiceResponse<List<Place>> sr1 = this.placeService.readAllByType(KPlaceTypeIDs.VILLAGE, 0, 0);
            if (sr1.getResponse() != null && sr1.getResponse().size() > 0) {
                for (Place place : sr1.getResponse()) {
                    if (StringUtils.equalsIgnoreCase(text, place.getTitle())) {
                        matchedPlace = place;
                        break;
                    }
                }
            }  
        }        
        return matchedPlace;
    }
    
    public static void main(String[] argv) {
        RoomoramaClient client = new RoomoramaClient();
        client.getUSDPHPExchangeRate();
        /*
        List<Room> rooms = client.searchRoomsMakati();
        for (Room room : rooms) {
            System.out.println("Room: " + room.getId() + " | " + room.getTitle());
            if (room.getImages().size() > 0) {
                for (String image : room.getImages()) {
                    try {
                        System.out.println("CX: image- " + image);
                        //File saveImage = new File("D:\\roomorama\\rm-photo-" + UUID.randomUUID().toString() + ".jpg");
                        //FileUtils.copyURLToFile(new URL(image), saveImage);
                    } catch (Exception ex) {
                        Logger.getLogger(RoomoramaClient.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
        */
    }
}
